Exception propagation

                  import kotlinx.coroutines.*
​
fun main() = runBlocking {
    val job = GlobalScope.launch { // root coroutine with launch
        println("Throwing exception from launch")
        throw IndexOutOfBoundsException() // Will be printed to the console by Thread.defaultUncaughtExceptionHandler
    }
    job.join()
    println("Joined failed job")
    val deferred = GlobalScope.async { // root coroutine with async
        println("Throwing exception from async")
        throw ArithmeticException() // Nothing is printed, relying on user to call await
    }
    try {
        deferred.await()
        println("Unreached")
    } catch (e: ArithmeticException) {
        println("Caught ArithmeticException")
    }
}
                
                    import kotlinx.coroutines.*
​
func main() = runBlocking {
    let job = GlobalScope.launch { // root coroutine with launch
        print("Throwing exception from launch")
        throw IndexOutOfBoundsException() // Will be printed to the console by Thread.defaultUncaughtExceptionHandler
    }
    job.join()
    print("Joined failed job")
    let deferred = GlobalScope.async { // root coroutine with async
        print("Throwing exception from async")
        throw ArithmeticException() // Nothing is printed, relying on user to call await
    }
    try {
        deferred.await()
        print("Unreached")
    } catch (e: ArithmeticException) {
        print("Caught ArithmeticException")
    }
}
                  

CoroutineExceptionHandler

                  val handler = CoroutineExceptionHandler { _, exception -> 
    println("CoroutineExceptionHandler got $exception") 
}
val job = GlobalScope.launch(handler) { // root coroutine, running in GlobalScope
    throw AssertionError()
}
val deferred = GlobalScope.async(handler) { // also root, but async instead of launch
    throw ArithmeticException() // Nothing will be printed, relying on user to call deferred.await()
}
joinAll(job, deferred)
                
                    let handler = CoroutineExceptionHandler { _, exception -> 
    print("CoroutineExceptionHandler got $exception") 
}
let job = GlobalScope.launch(handler) { // root coroutine, running in GlobalScope
    throw AssertionError()
}
let deferred = GlobalScope.async(handler) { // also root, but async instead of launch
    throw ArithmeticException() // Nothing will be printed, relying on user to call deferred.await()
}
joinAll(job, deferred)
                  

Cancellation and exceptions

                  val job = launch {
    val child = launch {
        try {
            delay(Long.MAX_VALUE)
        } finally {
            println("Child is cancelled")
        }
    }
    yield()
    println("Cancelling child")
    child.cancel()
    child.join()
    yield()
    println("Parent is not cancelled")
}
job.join()
                
                    let job = launch {
    let child = launch {
        try {
            delay(Long.MAX_VALUE)
        } finally {
            print("Child is cancelled")
        }
    }
    yield()
    print("Cancelling child")
    child.cancel()
    child.join()
    yield()
    print("Parent is not cancelled")
}
job.join()
                  
                  val handler = CoroutineExceptionHandler { _, exception -> 
    println("CoroutineExceptionHandler got $exception") 
}
val job = GlobalScope.launch(handler) {
    launch { // the first child
        try {
            delay(Long.MAX_VALUE)
        } finally {
            withContext(NonCancellable) {
                println("Children are cancelled, but exception is not handled until all children terminate")
                delay(100)
                println("The first child finished its non cancellable block")
            }
        }
    }
    launch { // the second child
        delay(10)
        println("Second child throws an exception")
        throw ArithmeticException()
    }
}
job.join()
                
                    let handler = CoroutineExceptionHandler { _, exception -> 
    print("CoroutineExceptionHandler got $exception") 
}
let job = GlobalScope.launch(handler) {
    launch { // the first child
        try {
            delay(Long.MAX_VALUE)
        } finally {
            withContext(NonCancellable) {
                print("Children are cancelled, but exception is not handled until all children terminate")
                delay(100)
                print("The first child finished its non cancellable block")
            }
        }
    }
    launch { // the second child
        delay(10)
        print("Second child throws an exception")
        throw ArithmeticException()
    }
}
job.join()
                  

Exceptions aggregation

                  import kotlinx.coroutines.*
import java.io.*
​
fun main() = runBlocking {
    val handler = CoroutineExceptionHandler { _, exception ->
        println("CoroutineExceptionHandler got $exception with suppressed ${exception.suppressed.contentToString()}")
    }
    val job = GlobalScope.launch(handler) {
        launch {
            try {
                delay(Long.MAX_VALUE) // it gets cancelled when another sibling fails with IOException
            } finally {
                throw ArithmeticException() // the second exception
            }
        }
        launch {
            delay(100)
            throw IOException() // the first exception
        }
        delay(Long.MAX_VALUE)
    }
    job.join()  
}
                
                    import kotlinx.coroutines.*
import java.io.*
​
func main() = runBlocking {
    let handler = CoroutineExceptionHandler { _, exception ->
        print("CoroutineExceptionHandler got $exception with suppressed ${exception.suppressed.contentToString()}")
    }
    let job = GlobalScope.launch(handler) {
        launch {
            try {
                delay(Long.MAX_VALUE) // it gets cancelled when another sibling fails with IOException
            } finally {
                throw ArithmeticException() // the second exception
            }
        }
        launch {
            delay(100)
            throw IOException() // the first exception
        }
        delay(Long.MAX_VALUE)
    }
    job.join()  
}
                  
                  val handler = CoroutineExceptionHandler { _, exception ->
    println("CoroutineExceptionHandler got $exception")
}
val job = GlobalScope.launch(handler) {
    val inner = launch { // all this stack of coroutines will get cancelled
        launch {
            launch {
                throw IOException() // the original exception
            }
        }
    }
    try {
        inner.join()
    } catch (e: CancellationException) {
        println("Rethrowing CancellationException with original cause")
        throw e // cancellation exception is rethrown, yet the original IOException gets to the handler  
    }
}
job.join()
                
                    let handler = CoroutineExceptionHandler { _, exception ->
    print("CoroutineExceptionHandler got $exception")
}
let job = GlobalScope.launch(handler) {
    let inner = launch { // all this stack of coroutines will get cancelled
        launch {
            launch {
                throw IOException() // the original exception
            }
        }
    }
    try {
        inner.join()
    } catch (e: CancellationException) {
        print("Rethrowing CancellationException with original cause")
        throw e // cancellation exception is rethrown, yet the original IOException gets to the handler  
    }
}
job.join()
                  

Supervision job

                  import kotlinx.coroutines.*
​
fun main() = runBlocking {
    val supervisor = SupervisorJob()
    with(CoroutineScope(coroutineContext + supervisor)) {
        // launch the first child -- its exception is ignored for this example (don't do this in practice!)
        val firstChild = launch(CoroutineExceptionHandler { _, _ ->  }) {
            println("The first child is failing")
            throw AssertionError("The first child is cancelled")
        }
        // launch the second child
        val secondChild = launch {
            firstChild.join()
            // Cancellation of the first child is not propagated to the second child
            println("The first child is cancelled: ${firstChild.isCancelled}, but the second one is still active")
            try {
                delay(Long.MAX_VALUE)
            } finally {
                // But cancellation of the supervisor is propagated
                println("The second child is cancelled because the supervisor was cancelled")
            }
        }
        // wait until the first child fails & completes
        firstChild.join()
        println("Cancelling the supervisor")
        supervisor.cancel()
        secondChild.join()
    }
}
                
                    import kotlinx.coroutines.*
​
func main() = runBlocking {
    let supervisor = SupervisorJob()
    with(CoroutineScope(coroutineContext + supervisor)) {
        // launch the first child -- its exception is ignored for this example (don't do this in practice!)
        let firstChild = launch(CoroutineExceptionHandler { _, _ ->  }) {
            print("The first child is failing")
            throw AssertionError("The first child is cancelled")
        }
        // launch the second child
        let secondChild = launch {
            firstChild.join()
            // Cancellation of the first child is not propagated to the second child
            print("The first child is cancelled: ${firstChild.isCancelled}, but the second one is still active")
            try {
                delay(Long.MAX_VALUE)
            } finally {
                // But cancellation of the supervisor is propagated
                print("The second child is cancelled because the supervisor was cancelled")
            }
        }
        // wait until the first child fails & completes
        firstChild.join()
        print("Cancelling the supervisor")
        supervisor.cancel()
        secondChild.join()
    }
}
                  

Supervision scope

                  import kotlin.coroutines.*
import kotlinx.coroutines.*
​
fun main() = runBlocking {
    try {
        supervisorScope {
            val child = launch {
                try {
                    println("The child is sleeping")
                    delay(Long.MAX_VALUE)
                } finally {
                    println("The child is cancelled")
                }
            }
            // Give our child a chance to execute and print using yield 
            yield()
            println("Throwing an exception from the scope")
            throw AssertionError()
        }
    } catch(e: AssertionError) {
        println("Caught an assertion error")
    }
}
                
                    import kotlin.coroutines.*
import kotlinx.coroutines.*
​
func main() = runBlocking {
    try {
        supervisorScope {
            let child = launch {
                try {
                    print("The child is sleeping")
                    delay(Long.MAX_VALUE)
                } finally {
                    print("The child is cancelled")
                }
            }
            // Give our child a chance to execute and print using yield 
            yield()
            print("Throwing an exception from the scope")
            throw AssertionError()
        }
    } catch(e: AssertionError) {
        print("Caught an assertion error")
    }
}
                  

Exceptions in supervised coroutines

                  import kotlin.coroutines.*
import kotlinx.coroutines.*
​
fun main() = runBlocking {
    val handler = CoroutineExceptionHandler { _, exception -> 
        println("CoroutineExceptionHandler got $exception") 
    }
    supervisorScope {
        val child = launch(handler) {
            println("The child throws an exception")
            throw AssertionError()
        }
        println("The scope is completing")
    }
    println("The scope is completed")
}
                
                    import kotlin.coroutines.*
import kotlinx.coroutines.*
​
func main() = runBlocking {
    let handler = CoroutineExceptionHandler { _, exception -> 
        print("CoroutineExceptionHandler got $exception") 
    }
    supervisorScope {
        let child = launch(handler) {
            print("The child throws an exception")
            throw AssertionError()
        }
        print("The scope is completing")
    }
    print("The scope is completed")
}